-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(deps): bump eslint-plugin-react from 7.35.0 to 7.37.2 #1359
Merged
github-actions
merged 2 commits into
main
from
dependabot/npm_and_yarn/eslint-plugin-react-7.37.2
Nov 5, 2024
Merged
feat(deps): bump eslint-plugin-react from 7.35.0 to 7.37.2 #1359
github-actions
merged 2 commits into
main
from
dependabot/npm_and_yarn/eslint-plugin-react-7.37.2
Nov 5, 2024
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dependabot
bot
added
dependencies
Pull requests that update a dependency file
javascript
Pull requests that update Javascript code
labels
Nov 1, 2024
Diff between eslint-plugin-react 7.35.0 and 7.37.2diff --git a/lib/util/annotations.js b/lib/util/annotations.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/annotations.js
+++ b/lib/util/annotations.js
@@ -13,5 +13,5 @@
* @param {ASTNode} node The AST node being checked.
* @param {Object} context
- * @returns {Boolean} True if the node is a type annotated props declaration, false if not.
+ * @returns {boolean} True if the node is a type annotated props declaration, false if not.
*/
function isAnnotatedFunctionPropsDeclaration(node, context) {
diff --git a/lib/util/ast.js b/lib/util/ast.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/ast.js
+++ b/lib/util/ast.js
@@ -93,5 +93,5 @@
/* TODO: properly warn on React.forwardRefs having typo properties
- if (nodeType === 'CallExpression') {
+ if (astUtil.isCallExpression(ASTNode)) {
const callee = ASTNode.callee;
const pragma = pragmaUtil.getFromContext(context);
@@ -149,5 +149,9 @@
*/
function getPropertyNameNode(node) {
- if (node.key || ['MethodDefinition', 'Property'].indexOf(node.type) !== -1) {
+ if (
+ node.key
+ || node.type === 'MethodDefinition'
+ || node.type === 'Property'
+ ) {
return node.key;
}
@@ -161,5 +165,5 @@
* Get properties name
* @param {Object} node - Property.
- * @returns {String} Property name.
+ * @returns {string} Property name.
*/
function getPropertyName(node) {
@@ -211,5 +215,5 @@
* @param {Object} context The node to check
* @param {ASTNode} node The node to check
- * @return {Boolean} true if it's the first node in its line
+ * @return {boolean} true if it's the first node in its line
*/
function isNodeFirstInLine(context, node) {
@@ -223,5 +227,5 @@
* Checks if the node is a function or arrow function expression.
* @param {ASTNode} node The node to check
- * @return {Boolean} true if it's a function-like expression
+ * @return {boolean} true if it's a function-like expression
*/
function isFunctionLikeExpression(node) {
@@ -232,5 +236,5 @@
* Checks if the node is a function.
* @param {ASTNode} node The node to check
- * @return {Boolean} true if it's a function
+ * @return {boolean} true if it's a function
*/
function isFunction(node) {
@@ -241,5 +245,5 @@
* Checks if node is a function declaration or expression or arrow function.
* @param {ASTNode} node The node to check
- * @return {Boolean} true if it's a function-like
+ * @return {boolean} true if it's a function-like
*/
function isFunctionLike(node) {
@@ -250,5 +254,5 @@
* Checks if the node is a class.
* @param {ASTNode} node The node to check
- * @return {Boolean} true if it's a class
+ * @return {boolean} true if it's a class
*/
function isClass(node) {
@@ -330,5 +334,5 @@
* Checks if a node is being assigned a value: props.bar = 'bar'
* @param {ASTNode} node The AST node being checked.
- * @returns {Boolean}
+ * @returns {boolean}
*/
function isAssignmentLHS(node) {
@@ -340,5 +344,18 @@
}
+function isTSAsExpression(node) {
+ return node && node.type === 'TSAsExpression';
+}
+
/**
+ * Matcher used to check whether given node is a `CallExpression`
+ * @param {ASTNode} node The AST node
+ * @returns {boolean} True if node is a `CallExpression`, false if not
+ */
+function isCallExpression(node) {
+ return node && node.type === 'CallExpression';
+}
+
+/**
* Extracts the expression node that is wrapped inside a TS type assertion
*
@@ -347,121 +364,120 @@
*/
function unwrapTSAsExpression(node) {
- if (node && node.type === 'TSAsExpression') return node.expression;
- return node;
+ return isTSAsExpression(node) ? node.expression : node;
}
function isTSTypeReference(node) {
if (!node) return false;
- const nodeType = node.type;
- return nodeType === 'TSTypeReference';
+
+ return node.type === 'TSTypeReference';
}
function isTSTypeAnnotation(node) {
- if (!node) return false;
- const nodeType = node.type;
- return nodeType === 'TSTypeAnnotation';
+ if (!node) { return false; }
+
+ return node.type === 'TSTypeAnnotation';
}
function isTSTypeLiteral(node) {
- if (!node) return false;
- const nodeType = node.type;
- return nodeType === 'TSTypeLiteral';
+ if (!node) { return false; }
+
+ return node.type === 'TSTypeLiteral';
}
function isTSIntersectionType(node) {
- if (!node) return false;
- const nodeType = node.type;
- return nodeType === 'TSIntersectionType';
+ if (!node) { return false; }
+
+ return node.type === 'TSIntersectionType';
}
function isTSInterfaceHeritage(node) {
- if (!node) return false;
- const nodeType = node.type;
- return nodeType === 'TSInterfaceHeritage';
+ if (!node) { return false; }
+
+ return node.type === 'TSInterfaceHeritage';
}
function isTSInterfaceDeclaration(node) {
- if (!node) return false;
- let nodeType = node.type;
- if (node.type === 'ExportNamedDeclaration' && node.declaration) {
- nodeType = node.declaration.type;
- }
- return nodeType === 'TSInterfaceDeclaration';
+ if (!node) { return false; }
+
+ return (node.type === 'ExportNamedDeclaration' && node.declaration
+ ? node.declaration.type
+ : node.type
+ ) === 'TSInterfaceDeclaration';
}
function isTSTypeDeclaration(node) {
- if (!node) return false;
- let nodeType = node.type;
- let nodeKind = node.kind;
- if (node.type === 'ExportNamedDeclaration' && node.declaration) {
- nodeType = node.declaration.type;
- nodeKind = node.declaration.kind;
- }
- return nodeType === 'VariableDeclaration' && nodeKind === 'type';
+ if (!node) { return false; }
+
+ const nodeToCheck = node.type === 'ExportNamedDeclaration' && node.declaration
+ ? node.declaration
+ : node;
+
+ return nodeToCheck.type === 'VariableDeclaration' && nodeToCheck.kind === 'type';
}
function isTSTypeAliasDeclaration(node) {
- if (!node) return false;
- let nodeType = node.type;
+ if (!node) { return false; }
+
if (node.type === 'ExportNamedDeclaration' && node.declaration) {
- nodeType = node.declaration.type;
- return nodeType === 'TSTypeAliasDeclaration' && node.exportKind === 'type';
+ return node.declaration.type === 'TSTypeAliasDeclaration' && node.exportKind === 'type';
}
- return nodeType === 'TSTypeAliasDeclaration';
+ return node.type === 'TSTypeAliasDeclaration';
}
function isTSParenthesizedType(node) {
- if (!node) return false;
- const nodeType = node.type;
- return nodeType === 'TSTypeAliasDeclaration';
+ if (!node) { return false; }
+
+ return node.type === 'TSTypeAliasDeclaration';
}
function isTSFunctionType(node) {
- if (!node) return false;
- const nodeType = node.type;
- return nodeType === 'TSFunctionType';
+ if (!node) { return false; }
+
+ return node.type === 'TSFunctionType';
}
function isTSTypeQuery(node) {
- if (!node) return false;
- const nodeType = node.type;
- return nodeType === 'TSTypeQuery';
+ if (!node) { return false; }
+
+ return node.type === 'TSTypeQuery';
}
function isTSTypeParameterInstantiation(node) {
- if (!node) return false;
- const nodeType = node.type;
- return nodeType === 'TSTypeParameterInstantiation';
+ if (!node) { return false; }
+
+ return node.type === 'TSTypeParameterInstantiation';
}
module.exports = {
- traverse,
findReturnStatement,
+ getComponentProperties,
getFirstNodeInLine,
+ getKeyValue,
getPropertyName,
getPropertyNameNode,
- getComponentProperties,
- getKeyValue,
- isParenthesized,
+ inConstructor,
isAssignmentLHS,
+ isCallExpression,
isClass,
isFunction,
+ isFunctionLike,
isFunctionLikeExpression,
- isFunctionLike,
- inConstructor,
isNodeFirstInLine,
- unwrapTSAsExpression,
- traverseReturns,
- isTSTypeReference,
+ isParenthesized,
+ isTSAsExpression,
+ isTSFunctionType,
+ isTSInterfaceDeclaration,
+ isTSInterfaceHeritage,
+ isTSIntersectionType,
+ isTSParenthesizedType,
+ isTSTypeAliasDeclaration,
isTSTypeAnnotation,
+ isTSTypeDeclaration,
isTSTypeLiteral,
- isTSIntersectionType,
- isTSInterfaceHeritage,
- isTSInterfaceDeclaration,
- isTSTypeAliasDeclaration,
- isTSParenthesizedType,
- isTSFunctionType,
+ isTSTypeParameterInstantiation,
isTSTypeQuery,
- isTSTypeParameterInstantiation,
- isTSTypeDeclaration,
+ isTSTypeReference,
+ traverse,
+ traverseReturns,
+ unwrapTSAsExpression,
};
diff --git a/lib/rules/boolean-prop-naming.js b/lib/rules/boolean-prop-naming.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/boolean-prop-naming.js
+++ b/lib/rules/boolean-prop-naming.js
@@ -11,4 +11,5 @@
const Components = require('../util/Components');
const propsUtil = require('../util/props');
+const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
const propWrapperUtil = require('../util/propWrapper');
@@ -19,4 +20,16 @@
const getText = eslintUtil.getText;
+/**
+ * Checks if prop is nested
+ * @param {Object} prop Property object, single prop type declaration
+ * @returns {boolean}
+ */
+function nestedPropTypes(prop) {
+ return (
+ prop.type === 'Property'
+ && astUtil.isCallExpression(prop.value)
+ );
+}
+
// ------------------------------------------------------------------------------
// Rule Definition
@@ -129,5 +142,5 @@
* Checks if prop is declared in flow way
* @param {Object} prop Property object, single prop type declaration
- * @returns {Boolean}
+ * @returns {boolean}
*/
function flowCheck(prop) {
@@ -142,5 +155,5 @@
* Checks if prop is declared in regular way
* @param {Object} prop Property object, single prop type declaration
- * @returns {Boolean}
+ * @returns {boolean}
*/
function regularCheck(prop) {
@@ -164,16 +177,4 @@
/**
- * Checks if prop is nested
- * @param {Object} prop Property object, single prop type declaration
- * @returns {Boolean}
- */
- function nestedPropTypes(prop) {
- return (
- prop.type === 'Property'
- && prop.value.type === 'CallExpression'
- );
- }
-
- /**
* Runs recursive check on all proptypes
* @param {Array} proptypes A list of Property object (for each proptype defined)
@@ -181,13 +182,15 @@
*/
function runCheck(proptypes, addInvalidProp) {
- (proptypes || []).forEach((prop) => {
- if (config.validateNested && nestedPropTypes(prop)) {
- runCheck(prop.value.arguments[0].properties, addInvalidProp);
- return;
- }
- if (flowCheck(prop) || regularCheck(prop) || tsCheck(prop)) {
- addInvalidProp(prop);
- }
- });
+ if (proptypes) {
+ proptypes.forEach((prop) => {
+ if (config.validateNested && nestedPropTypes(prop)) {
+ runCheck(prop.value.arguments[0].properties, addInvalidProp);
+ return;
+ }
+ if (flowCheck(prop) || regularCheck(prop) || tsCheck(prop)) {
+ addInvalidProp(prop);
+ }
+ });
+ }
}
@@ -257,12 +260,14 @@
}
- const annotationTypeParams = component.node.parent.id.typeAnnotation.typeAnnotation.typeParameters;
+ const annotationTypeArguments = propsUtil.getTypeArguments(
+ component.node.parent.id.typeAnnotation.typeAnnotation
+ );
if (
- annotationTypeParams && (
- annotationTypeParams.type === 'TSTypeParameterInstantiation'
- || annotationTypeParams.type === 'TypeParameterInstantiation'
+ annotationTypeArguments && (
+ annotationTypeArguments.type === 'TSTypeParameterInstantiation'
+ || annotationTypeArguments.type === 'TypeParameterInstantiation'
)
) {
- return annotationTypeParams.params.find(
+ return annotationTypeArguments.params.find(
(param) => param.type === 'TSTypeReference' || param.type === 'GenericTypeAnnotation'
);
@@ -310,5 +315,5 @@
if (
node.value
- && node.value.type === 'CallExpression'
+ && astUtil.isCallExpression(node.value)
&& propWrapperUtil.isPropWrapperFunction(
context,
@@ -336,5 +341,5 @@
const right = node.parent.right;
if (
- right.type === 'CallExpression'
+ astUtil.isCallExpression(right)
&& propWrapperUtil.isPropWrapperFunction(
context,
diff --git a/lib/rules/button-has-type.js b/lib/rules/button-has-type.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/button-has-type.js
+++ b/lib/rules/button-has-type.js
@@ -29,4 +29,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
@@ -150,5 +151,10 @@
const props = node.arguments[1].properties;
- const typeProp = props.find((prop) => prop.key && prop.key.name === 'type');
+ const typeProp = props.find((prop) => (
+ 'key' in prop
+ && prop.key
+ && 'name' in prop.key
+ && prop.key.name === 'type'
+ ));
if (!typeProp) {
@@ -157,5 +163,5 @@
}
- checkExpression(node, typeProp.value);
+ checkExpression(node, 'value' in typeProp ? typeProp.value : undefined);
},
};
diff --git a/lib/rules/checked-requires-onchange-or-readonly.js b/lib/rules/checked-requires-onchange-or-readonly.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/checked-requires-onchange-or-readonly.js
+++ b/lib/rules/checked-requires-onchange-or-readonly.js
@@ -25,5 +25,5 @@
/**
- * @param {string[]} properties
+ * @param {object[]} properties
* @param {string} keyName
* @returns {Set<string>}
@@ -42,4 +42,5 @@
}
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
diff --git a/lib/util/Components.js b/lib/util/Components.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/Components.js
+++ b/lib/util/Components.js
@@ -71,5 +71,5 @@
*
* @param {ASTNode} node The AST node being added.
- * @param {Number} confidence Confidence in the component detection (0=banned, 1=maybe, 2=yes)
+ * @param {number} confidence Confidence in the component detection (0=banned, 1=maybe, 2=yes)
* @returns {Object} Added component object
*/
@@ -184,5 +184,5 @@
* Components for which we are not confident are not counted
*
- * @returns {Number} Components list length
+ * @returns {number} Components list length
*/
length() {
@@ -304,18 +304,18 @@
/**
- * @param {ASTNode} ASTNode
+ * @param {ASTNode} node
* @param {boolean=} strict
* @returns {boolean}
*/
- isReturningJSX(ASTNode, strict) {
- return jsxUtil.isReturningJSX(context, ASTNode, strict, true);
+ isReturningJSX(node, strict) {
+ return jsxUtil.isReturningJSX(context, node, strict, true);
},
- isReturningJSXOrNull(ASTNode, strict) {
- return jsxUtil.isReturningJSX(context, ASTNode, strict);
+ isReturningJSXOrNull(node, strict) {
+ return jsxUtil.isReturningJSX(context, node, strict);
},
- isReturningOnlyNull(ASTNode) {
- return jsxUtil.isReturningOnlyNull(ASTNode, context);
+ isReturningOnlyNull(node) {
+ return jsxUtil.isReturningOnlyNull(node, context);
},
@@ -408,5 +408,5 @@
isPragmaComponentWrapper(node) {
- if (!node || node.type !== 'CallExpression') {
+ if (!astUtil.isCallExpression(node)) {
return false;
}
@@ -568,5 +568,11 @@
// for case abc = { [someobject.somekey]: props => { ... return not-jsx } }
- if (node.parent && node.parent.key && node.parent.key.type === 'MemberExpression' && !utils.isReturningJSX(node) && !utils.isReturningOnlyNull(node)) {
+ if (
+ node.parent
+ && node.parent.key
+ && node.parent.key.type === 'MemberExpression'
+ && !utils.isReturningJSX(node)
+ && !utils.isReturningOnlyNull(node)
+ ) {
return undefined;
}
@@ -578,5 +584,8 @@
)
) {
- if (isFirstLetterCapitalized(node.parent.key.name) && utils.isReturningJSX(node)) {
+ if (
+ isFirstLetterCapitalized(node.parent.key.name)
+ && utils.isReturningJSX(node)
+ ) {
return node;
}
@@ -642,5 +651,5 @@
*
* @param {ASTNode} node The AST node being checked (must be a MemberExpression).
- * @returns {ASTNode} component node, null if we cannot find the component
+ * @returns {ASTNode | null} component node, null if we cannot find the component
*/
getRelatedComponent(node) {
@@ -752,8 +761,8 @@
* @param {ASTNode} node The AST node being searched. (expects CallExpression)
* @param {('useCallback'|'useContext'|'useDebugValue'|'useEffect'|'useImperativeHandle'|'useLayoutEffect'|'useMemo'|'useReducer'|'useRef'|'useState')[]} [expectedHookNames] React hook names to which search is limited.
- * @returns {Boolean} True if the node is a call to a React hook
+ * @returns {boolean} True if the node is a call to a React hook
*/
isReactHookCall(node, expectedHookNames) {
- if (node.type !== 'CallExpression') {
+ if (!astUtil.isCallExpression(node)) {
return false;
}
@@ -799,6 +808,12 @@
const hookResolvedDefs = potentialHookReference && potentialHookReference.resolved.defs;
- const localHookName = (isPotentialReactHookCall && node.callee.property.name)
- || (isPotentialHookCall && potentialHookReference && node.callee.name);
+ const localHookName = (
+ isPotentialReactHookCall
+ && node.callee.property.name
+ ) || (
+ isPotentialHookCall
+ && potentialHookReference
+ && node.callee.name
+ );
const isHookShadowed = isPotentialHookCall
&& hookResolvedDefs
@@ -877,9 +892,9 @@
}
- node = utils.getStatelessComponent(node);
- if (!node) {
+ const cNode = utils.getStatelessComponent(node);
+ if (!cNode) {
return;
}
- components.add(node, 2);
+ components.add(cNode, 2);
},
diff --git a/lib/util/componentUtil.js b/lib/util/componentUtil.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/componentUtil.js
+++ b/lib/util/componentUtil.js
@@ -175,5 +175,7 @@
*/
function isStateMemberExpression(node) {
- return node.type === 'MemberExpression' && node.object.type === 'ThisExpression' && node.property.name === 'state';
+ return node.type === 'MemberExpression'
+ && node.object.type === 'ThisExpression'
+ && node.property.name === 'state';
}
diff --git a/lib/util/defaultProps.js b/lib/util/defaultProps.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/defaultProps.js
+++ b/lib/util/defaultProps.js
@@ -27,5 +27,5 @@
}
if (
- node.type === 'CallExpression'
+ astUtil.isCallExpression(node)
&& propWrapperUtil.isPropWrapperFunction(context, node.callee.name)
&& node.arguments && node.arguments[0]
diff --git a/lib/rules/destructuring-assignment.js b/lib/rules/destructuring-assignment.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/destructuring-assignment.js
+++ b/lib/rules/destructuring-assignment.js
@@ -182,4 +182,23 @@
}
+ // valid-jsdoc cannot read function types
+ // eslint-disable-next-line valid-jsdoc
+ /**
+ * Find a parent that satisfy the given predicate
+ * @param {ASTNode} node
+ * @param {(node: ASTNode) => boolean} predicate
+ * @returns {ASTNode | undefined}
+ */
+ function findParent(node, predicate) {
+ let n = node;
+ while (n) {
+ if (predicate(n)) {
+ return n;
+ }
+ n = n.parent;
+ }
+ return undefined;
+ }
+
return {
@@ -197,10 +216,5 @@
MemberExpression(node) {
- let scope = getScope(context, node);
- let SFCComponent = components.get(scope.block);
- while (!SFCComponent && scope.upper && scope.upper !== scope) {
- SFCComponent = components.get(scope.upper.block);
- scope = scope.upper;
- }
+ const SFCComponent = utils.getParentStatelessComponent(node);
if (SFCComponent) {
handleSFCUsage(node);
@@ -213,4 +227,23 @@
},
+ TSQualifiedName(node) {
+ if (configuration !== 'always') {
+ return;
+ }
+ // handle `typeof props.a.b`
+ if (node.left.type === 'Identifier'
+ && node.left.name === sfcParams.propsName()
+ && findParent(node, (n) => n.type === 'TSTypeQuery')
+ && utils.getParentStatelessComponent(node)
+ ) {
+ report(context, messages.useDestructAssignment, 'useDestructAssignment', {
+ node,
+ data: {
+ type: 'props',
+ },
+ });
+ }
+ },
+
VariableDeclarator(node) {
const classComponent = utils.getParentComponent(node);
@@ -258,4 +291,5 @@
return;
}
+
// Skip if props is used elsewhere
if (propsRefs.length > 1) {
diff --git a/lib/rules/display-name.js b/lib/rules/display-name.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/display-name.js
+++ b/lib/rules/display-name.js
@@ -74,10 +74,11 @@
* Checks if React.forwardRef is nested inside React.memo
* @param {ASTNode} node The AST node being checked.
- * @returns {Boolean} True if React.forwardRef is nested inside React.memo, false if not.
+ * @returns {boolean} True if React.forwardRef is nested inside React.memo, false if not.
*/
function isNestedMemo(node) {
- const argumentIsCallExpression = node.arguments && node.arguments[0] && node.arguments[0].type === 'CallExpression';
-
- return node.type === 'CallExpression' && argumentIsCallExpression && utils.isPragmaComponentWrapper(node);
+ return astUtil.isCallExpression(node)
+ && node.arguments
+ && astUtil.isCallExpression(node.arguments[0])
+ && utils.isPragmaComponentWrapper(node);
}
@@ -112,5 +113,5 @@
* Checks if the component have a name set by the transpiler
* @param {ASTNode} node The AST node being checked.
- * @returns {Boolean} True if component has a name, false if not.
+ * @returns {boolean} True if component has a name, false if not.
*/
function hasTranspilerName(node) {
@@ -199,5 +200,5 @@
return;
}
- markDisplayNameAsDeclared(component.node.type === 'TSAsExpression' ? component.node.expression : component.node);
+ markDisplayNameAsDeclared(astUtil.unwrapTSAsExpression(component.node));
},
diff --git a/lib/util/error.js b/lib/util/error.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/error.js
+++ b/lib/util/error.js
@@ -3,5 +3,5 @@
/**
* Logs out a message if there is no format option set.
- * @param {String} message - Message to log.
+ * @param {string} message - Message to log.
*/
function error(message) {
diff --git a/lib/rules/forbid-component-props.js b/lib/rules/forbid-component-props.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/forbid-component-props.js
+++ b/lib/rules/forbid-component-props.js
@@ -53,4 +53,9 @@
items: { type: 'string' },
},
+ allowedForPatterns: {
+ type: 'array',
+ uniqueItems: true,
+ items: { type: 'string' },
+ },
message: { type: 'string' },
},
@@ -67,10 +72,18 @@
items: { type: 'string' },
},
+ disallowedForPatterns: {
+ type: 'array',
+ uniqueItems: true,
+ minItems: 1,
+ items: { type: 'string' },
+ },
message: { type: 'string' },
},
- required: ['disallowedFor'],
+ anyOf: [
+ { required: ['disallowedFor'] },
+ { required: ['disallowedForPatterns'] },
+ ],
additionalProperties: false,
},
-
{
type: 'object',
@@ -82,4 +95,9 @@
items: { type: 'string' },
},
+ allowedForPatterns: {
+ type: 'array',
+ uniqueItems: true,
+ items: { type: 'string' },
+ },
message: { type: 'string' },
},
@@ -96,7 +114,16 @@
items: { type: 'string' },
},
+ disallowedForPatterns: {
+ type: 'array',
+ uniqueItems: true,
+ minItems: 1,
+ items: { type: 'string' },
+ },
message: { type: 'string' },
},
- required: ['disallowedFor'],
+ anyOf: [
+ { required: ['disallowedFor'] },
+ { required: ['disallowedForPatterns'] },
+ ],
additionalProperties: false,
},
@@ -115,6 +142,8 @@
const prop = propName || propPattern;
const options = {
- allowList: typeof value === 'string' ? [] : (value.allowedFor || []),
- disallowList: typeof value === 'string' ? [] : (value.disallowedFor || []),
+ allowList: [].concat(value.allowedFor || []),
+ allowPatternList: [].concat(value.allowedForPatterns || []),
+ disallowList: [].concat(value.disallowedFor || []),
+ disallowPatternList: [].concat(value.disallowedForPatterns || []),
message: typeof value === 'string' ? null : value.message,
isPattern: !!value.propNamePattern,
@@ -141,8 +170,38 @@
}
+ function checkIsTagForbiddenByAllowOptions() {
+ if (options.allowList.indexOf(tagName) !== -1) {
+ return false;
+ }
+
+ if (options.allowPatternList.length === 0) {
+ return true;
+ }
+
+ return options.allowPatternList.every(
+ (pattern) => !minimatch(tagName, pattern)
+ );
+ }
+
+ function checkIsTagForbiddenByDisallowOptions() {
+ if (options.disallowList.indexOf(tagName) !== -1) {
+ return true;
+ }
+
+ if (options.disallowPatternList.length === 0) {
+ return false;
+ }
+
+ return options.disallowPatternList.some(
+ (pattern) => minimatch(tagName, pattern)
+ );
+ }
+
+ const hasDisallowOptions = options.disallowList.length > 0 || options.disallowPatternList.length > 0;
+
// disallowList should have a least one item (schema configuration)
- const isTagForbidden = options.disallowList.length > 0
- ? options.disallowList.indexOf(tagName) !== -1
- : options.allowList.indexOf(tagName) === -1;
+ const isTagForbidden = hasDisallowOptions
+ ? checkIsTagForbiddenByDisallowOptions()
+ : checkIsTagForbiddenByAllowOptions();
// if the tagName is undefined (`<this.something>`), we assume it's a forbidden element
diff --git a/lib/rules/forbid-elements.js b/lib/rules/forbid-elements.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/forbid-elements.js
+++ b/lib/rules/forbid-elements.js
@@ -21,4 +21,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
@@ -106,11 +107,9 @@
}
- const argType = argument.type;
-
- if (argType === 'Identifier' && /^[A-Z_]/.test(argument.name)) {
+ if (argument.type === 'Identifier' && /^[A-Z_]/.test(argument.name)) {
reportIfForbidden(argument.name, argument);
- } else if (argType === 'Literal' && /^[a-z][^.]*$/.test(argument.value)) {
+ } else if (argument.type === 'Literal' && /^[a-z][^.]*$/.test(String(argument.value))) {
reportIfForbidden(argument.value, argument);
- } else if (argType === 'MemberExpression') {
+ } else if (argument.type === 'MemberExpression') {
reportIfForbidden(getText(context, argument), argument);
}
diff --git a/lib/rules/forbid-foreign-prop-types.js b/lib/rules/forbid-foreign-prop-types.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/forbid-foreign-prop-types.js
+++ b/lib/rules/forbid-foreign-prop-types.js
@@ -14,4 +14,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
@@ -109,5 +110,7 @@
&& !isAllowedAssignment(node)
)) || (
+ // @ts-expect-error The JSXText type is not present in the estree type definitions
(node.property.type === 'Literal' || node.property.type === 'JSXText')
+ && 'value' in node.property
&& node.property.value === 'propTypes'
&& !ast.isAssignmentLHS(node)
@@ -122,5 +125,9 @@
ObjectPattern(node) {
- const propTypesNode = node.properties.find((property) => property.type === 'Property' && property.key.name === 'propTypes');
+ const propTypesNode = node.properties.find((property) => (
+ property.type === 'Property'
+ && 'name' in property.key
+ && property.key.name === 'propTypes'
+ ));
if (propTypesNode) {
diff --git a/lib/rules/forbid-prop-types.js b/lib/rules/forbid-prop-types.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/forbid-prop-types.js
+++ b/lib/rules/forbid-prop-types.js
@@ -27,4 +27,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
@@ -135,5 +136,5 @@
value = value.object;
}
- if (value.type === 'CallExpression') {
+ if (astUtil.isCallExpression(value)) {
if (!isPropTypesPackage(value.callee)) {
return;
@@ -159,27 +160,23 @@
function checkNode(node) {
- switch (node && node.type) {
- case 'ObjectExpression':
- checkProperties(node.properties);
- break;
- case 'Identifier': {
- const propTypesObject = variableUtil.findVariableByName(context, node, node.name);
- if (propTypesObject && propTypesObject.properties) {
- checkProperties(propTypesObject.properties);
- }
- break;
+ if (!node) {
+ return;
+ }
+
+ if (node.type === 'ObjectExpression') {
+ checkProperties(node.properties);
+ } else if (node.type === 'Identifier') {
+ const propTypesObject = variableUtil.findVariableByName(context, node, node.name);
+ if (propTypesObject && propTypesObject.properties) {
+ checkProperties(propTypesObject.properties);
}
- case 'CallExpression': {
- const innerNode = node.arguments && node.arguments[0];
- if (
- propWrapperUtil.isPropWrapperFunction(context, getText(context, node.callee))
+ } else if (astUtil.isCallExpression(node)) {
+ const innerNode = node.arguments && node.arguments[0];
+ if (
+ propWrapperUtil.isPropWrapperFunction(context, getText(context, node.callee))
&& innerNode
- ) {
- checkNode(innerNode);
- }
- break;
+ ) {
+ checkNode(innerNode);
}
- default:
- break;
}
}
@@ -197,5 +194,7 @@
if (node.specifiers.length >= 1) {
const propTypesSpecifier = node.specifiers.find((specifier) => (
- specifier.imported && specifier.imported.name === 'PropTypes'
+ 'imported' in specifier
+ && specifier.imported
+ && specifier.imported.name === 'PropTypes'
));
if (propTypesSpecifier) {
@@ -233,10 +232,11 @@
}
- checkNode(node.parent.right);
+ checkNode('right' in node.parent && node.parent.right);
},
CallExpression(node) {
if (
- node.callee.object
+ node.callee.type === 'MemberExpression'
+ && node.callee.object
&& !isPropTypesPackage(node.callee.object)
&& !propsUtil.isPropTypesDeclaration(node.callee)
@@ -247,7 +247,10 @@
if (
node.arguments.length > 0
- && (node.callee.name === 'shape' || astUtil.getPropertyName(node.callee) === 'shape')
+ && (
+ ('name' in node.callee && node.callee.name === 'shape')
+ || astUtil.getPropertyName(node.callee) === 'shape'
+ )
) {
- checkProperties(node.arguments[0].properties);
+ checkProperties('properties' in node.arguments[0] && node.arguments[0].properties);
}
},
@@ -272,5 +275,5 @@
ObjectExpression(node) {
node.properties.forEach((property) => {
- if (!property.key) {
+ if (!('key' in property) || !property.key) {
return;
}
diff --git a/lib/rules/function-component-definition.js b/lib/rules/function-component-definition.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/function-component-definition.js
+++ b/lib/rules/function-component-definition.js
@@ -11,4 +11,5 @@
const reportC = require('../util/report');
const getText = require('../util/eslint').getText;
+const propsUtil = require('../util/props');
// ------------------------------------------------------------------------------
@@ -35,10 +36,10 @@
function hasOneUnconstrainedTypeParam(node) {
- const nodeTypeParams = node.typeParameters;
+ const nodeTypeArguments = propsUtil.getTypeArguments(node);
- return nodeTypeParams
- && nodeTypeParams.params
- && nodeTypeParams.params.length === 1
- && !nodeTypeParams.params[0].constraint;
+ return nodeTypeArguments
+ && nodeTypeArguments.params
+ && nodeTypeArguments.params.length === 1
+ && !nodeTypeArguments.params[0].constraint;
}
@@ -203,9 +204,10 @@
}
+ const nodeTypeArguments = propsUtil.getTypeArguments(node);
return (fixer) => fixer.replaceTextRange(
options.range,
buildFunction(options.template, {
typeAnnotation,
- typeParams: getNodeText(node.typeParameters, source),
+ typeParams: getNodeText(nodeTypeArguments, source),
params: getParams(node, source),
returnType: getNodeText(node.returnType, source),
diff --git a/lib/rules/hook-use-state.js b/lib/rules/hook-use-state.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/hook-use-state.js
+++ b/lib/rules/hook-use-state.js
@@ -27,4 +27,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
diff --git a/index.js b/index.js
index v7.35.0..v7.37.2 100644
--- a/index.js
+++ b/index.js
@@ -12,5 +12,5 @@
/**
* @param {object} rules - rules object mapping rule name to rule module
- * @returns {Record<string, 2>}
+ * @returns {Record<string, 2 | 'error'>}
*/
function configureAsError(rules) {
@@ -18,9 +18,13 @@
}
+/** @type {Partial<typeof allRules>} */
const activeRules = filterRules(allRules, (rule) => !rule.meta.deprecated);
+/** @type {Record<keyof typeof activeRules, 2 | 'error'>} */
const activeRulesConfig = configureAsError(activeRules);
+/** @type {Partial<typeof allRules>} */
const deprecatedRules = filterRules(allRules, (rule) => rule.meta.deprecated);
+/** @type {['react']} */
// for legacy config system
const plugins = [
@@ -28,80 +32,86 @@
];
-const plugin = {
- deprecatedRules,
- rules: allRules,
- configs: {
- recommended: {
- plugins,
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
- },
+const configs = {
+ recommended: {
+ plugins,
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
},
- rules: {
- 'react/display-name': 2,
- 'react/jsx-key': 2,
- 'react/jsx-no-comment-textnodes': 2,
- 'react/jsx-no-duplicate-props': 2,
- 'react/jsx-no-target-blank': 2,
- 'react/jsx-no-undef': 2,
- 'react/jsx-uses-react': 2,
- 'react/jsx-uses-vars': 2,
- 'react/no-children-prop': 2,
- 'react/no-danger-with-children': 2,
- 'react/no-deprecated': 2,
- 'react/no-direct-mutation-state': 2,
- 'react/no-find-dom-node': 2,
- 'react/no-is-mounted': 2,
- 'react/no-render-return-value': 2,
- 'react/no-string-refs': 2,
- 'react/no-unescaped-entities': 2,
- 'react/no-unknown-property': 2,
- 'react/no-unsafe': 0,
- 'react/prop-types': 2,
- 'react/react-in-jsx-scope': 2,
- 'react/require-render-return': 2,
- },
},
- all: {
- plugins,
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
- },
+ rules: {
+ 'react/display-name': 2,
+ 'react/jsx-key': 2,
+ 'react/jsx-no-comment-textnodes': 2,
+ 'react/jsx-no-duplicate-props': 2,
+ 'react/jsx-no-target-blank': 2,
+ 'react/jsx-no-undef': 2,
+ 'react/jsx-uses-react': 2,
+ 'react/jsx-uses-vars': 2,
+ 'react/no-children-prop': 2,
+ 'react/no-danger-with-children': 2,
+ 'react/no-deprecated': 2,
+ 'react/no-direct-mutation-state': 2,
+ 'react/no-find-dom-node': 2,
+ 'react/no-is-mounted': 2,
+ 'react/no-render-return-value': 2,
+ 'react/no-string-refs': 2,
+ 'react/no-unescaped-entities': 2,
+ 'react/no-unknown-property': 2,
+ 'react/no-unsafe': 0,
+ 'react/prop-types': 2,
+ 'react/react-in-jsx-scope': 2,
+ 'react/require-render-return': 2,
+ },
+ },
+ all: {
+ plugins,
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
},
- rules: activeRulesConfig,
},
- 'jsx-runtime': {
- plugins,
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
- },
- jsxPragma: null, // for @typescript/eslint-parser
+ rules: activeRulesConfig,
+ },
+ 'jsx-runtime': {
+ plugins,
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
},
- rules: {
- 'react/react-in-jsx-scope': 0,
- 'react/jsx-uses-react': 0,
- },
+ jsxPragma: null, // for @typescript/eslint-parser
},
+ rules: {
+ 'react/react-in-jsx-scope': 0,
+ 'react/jsx-uses-react': 0,
+ },
},
};
-plugin.configs.flat = {
+/** @typedef {{ plugins: { react: typeof plugin }, rules: import('eslint').Linter.RulesRecord, languageOptions: { parserOptions: import('eslint').Linter.ParserOptions } }} ReactFlatConfig */
+
+/** @type {{ deprecatedRules: typeof deprecatedRules, rules: typeof allRules, configs: typeof configs & { flat?: Record<string, ReactFlatConfig> }}} */
+const plugin = {
+ deprecatedRules,
+ rules: allRules,
+ configs,
+};
+
+/** @type {Record<string, ReactFlatConfig>} */
+configs.flat = {
recommended: {
plugins: { react: plugin },
- rules: plugin.configs.recommended.rules,
- languageOptions: { parserOptions: plugin.configs.recommended.parserOptions },
+ rules: configs.recommended.rules,
+ languageOptions: { parserOptions: configs.recommended.parserOptions },
},
all: {
plugins: { react: plugin },
- rules: plugin.configs.all.rules,
- languageOptions: { parserOptions: plugin.configs.all.parserOptions },
+ rules: configs.all.rules,
+ languageOptions: { parserOptions: configs.all.parserOptions },
},
'jsx-runtime': {
plugins: { react: plugin },
- rules: plugin.configs['jsx-runtime'].rules,
- languageOptions: { parserOptions: plugin.configs['jsx-runtime'].parserOptions },
+ rules: configs['jsx-runtime'].rules,
+ languageOptions: { parserOptions: configs['jsx-runtime'].parserOptions },
},
};
diff --git a/lib/rules/index.js b/lib/rules/index.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/index.js
+++ b/lib/rules/index.js
@@ -16,4 +16,5 @@
'forbid-foreign-prop-types': require('./forbid-foreign-prop-types'),
'forbid-prop-types': require('./forbid-prop-types'),
+ 'forward-ref-uses-ref': require('./forward-ref-uses-ref'),
'function-component-definition': require('./function-component-definition'),
'hook-use-state': require('./hook-use-state'),
diff --git a/lib/util/isCreateContext.js b/lib/util/isCreateContext.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/isCreateContext.js
+++ b/lib/util/isCreateContext.js
@@ -1,27 +1,30 @@
'use strict';
+const astUtil = require('./ast');
+
/**
* Checks if the node is a React.createContext call
* @param {ASTNode} node - The AST node being checked.
- * @returns {Boolean} - True if node is a React.createContext call, false if not.
+ * @returns {boolean} - True if node is a React.createContext call, false if not.
*/
module.exports = function isCreateContext(node) {
if (
node.init
- && node.init.type === 'CallExpression'
&& node.init.callee
- && node.init.callee.name === 'createContext'
) {
- return true;
- }
+ if (
+ astUtil.isCallExpression(node.init)
+ && node.init.callee.name === 'createContext'
+ ) {
+ return true;
+ }
- if (
- node.init
- && node.init.callee
- && node.init.callee.type === 'MemberExpression'
- && node.init.callee.property
- && node.init.callee.property.name === 'createContext'
- ) {
- return true;
+ if (
+ node.init.callee.type === 'MemberExpression'
+ && node.init.callee.property
+ && node.init.callee.property.name === 'createContext'
+ ) {
+ return true;
+ }
}
@@ -30,22 +33,20 @@
&& node.expression.type === 'AssignmentExpression'
&& node.expression.operator === '='
- && node.expression.right.type === 'CallExpression'
+ && astUtil.isCallExpression(node.expression.right)
&& node.expression.right.callee
- && node.expression.right.callee.name === 'createContext'
) {
- return true;
- }
+ const right = node.expression.right;
- if (
- node.expression
- && node.expression.type === 'AssignmentExpression'
- && node.expression.operator === '='
- && node.expression.right.type === 'CallExpression'
- && node.expression.right.callee
- && node.expression.right.callee.type === 'MemberExpression'
- && node.expression.right.callee.property
- && node.expression.right.callee.property.name === 'createContext'
- ) {
- return true;
+ if (right.callee.name === 'createContext') {
+ return true;
+ }
+
+ if (
+ right.callee.type === 'MemberExpression'
+ && right.callee.property
+ && right.callee.property.name === 'createContext'
+ ) {
+ return true;
+ }
}
diff --git a/lib/util/isCreateElement.js b/lib/util/isCreateElement.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/isCreateElement.js
+++ b/lib/util/isCreateElement.js
@@ -11,7 +11,10 @@
*/
module.exports = function isCreateElement(context, node) {
+ if (!node.callee) {
+ return false;
+ }
+
if (
- node.callee
- && node.callee.type === 'MemberExpression'
+ node.callee.type === 'MemberExpression'
&& node.callee.property.name === 'createElement'
&& node.callee.object
@@ -22,7 +25,5 @@
if (
- node
- && node.callee
- && node.callee.name === 'createElement'
+ node.callee.name === 'createElement'
&& isDestructuredFromPragmaImport(context, node, 'createElement')
) {
diff --git a/lib/util/isDestructuredFromPragmaImport.js b/lib/util/isDestructuredFromPragmaImport.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/isDestructuredFromPragmaImport.js
+++ b/lib/util/isDestructuredFromPragmaImport.js
@@ -1,4 +1,5 @@
'use strict';
+const astUtil = require('./ast');
const pragmaUtil = require('./pragma');
const variableUtil = require('./variable');
@@ -23,6 +24,6 @@
if (
latestDef.node.init.type === 'MemberExpression'
- && latestDef.node.init.object.type === 'Identifier'
- && latestDef.node.init.object.name === pragma
+ && latestDef.node.init.object.type === 'Identifier'
+ && latestDef.node.init.object.name === pragma
) {
return true;
@@ -31,5 +32,5 @@
if (
latestDef.node.init.type === 'Identifier'
- && latestDef.node.init.name === pragma
+ && latestDef.node.init.name === pragma
) {
return true;
@@ -40,5 +41,5 @@
// get "require('react')" from: "{variable} = require('react')"
- if (latestDef.node.init.type === 'CallExpression') {
+ if (astUtil.isCallExpression(latestDef.node.init)) {
requireExpression = latestDef.node.init;
}
@@ -46,6 +47,6 @@
if (
!requireExpression
- && latestDef.node.init.type === 'MemberExpression'
- && latestDef.node.init.object.type === 'CallExpression'
+ && latestDef.node.init.type === 'MemberExpression'
+ && astUtil.isCallExpression(latestDef.node.init.object)
) {
requireExpression = latestDef.node.init.object;
@@ -55,8 +56,8 @@
if (
requireExpression
- && requireExpression.callee
- && requireExpression.callee.name === 'require'
- && requireExpression.arguments[0]
- && requireExpression.arguments[0].value === pragma.toLocaleLowerCase()
+ && requireExpression.callee
+ && requireExpression.callee.name === 'require'
+ && requireExpression.arguments[0]
+ && requireExpression.arguments[0].value === pragma.toLocaleLowerCase()
) {
return true;
@@ -69,6 +70,6 @@
if (
latestDef.parent
- && latestDef.parent.type === 'ImportDeclaration'
- && latestDef.parent.source.value === pragma.toLocaleLowerCase()
+ && latestDef.parent.type === 'ImportDeclaration'
+ && latestDef.parent.source.value === pragma.toLocaleLowerCase()
) {
return true;
diff --git a/lib/util/isFirstLetterCapitalized.js b/lib/util/isFirstLetterCapitalized.js
index v7.35.0..v7.37.2 100644
--- a/lib/util/isFirstLetterCapitalized.js
+++ b/lib/util/isFirstLetterCapitalized.js
@@ -3,8 +3,8 @@
/**
* Check if the first letter of a string is capitalized.
- * @param {String} word String to check
- * @returns {Boolean} True if first letter is capitalized.
+ * @param {string} word String to check
+ * @returns {boolean} True if first letter is capitalized.
*/
-function isFirstLetterCapitalized(word) {
+module.exports = function isFirstLetterCapitalized(word) {
if (!word) {
return false;
@@ -12,5 +12,3 @@
const firstLetter = word.replace(/^_+/, '').charAt(0);
return firstLetter.toUpperCase() === firstLetter;
-}
-
-module.exports = isFirstLetterCapitalized;
+};
diff --git a/lib/rules/jsx-closing-bracket-location.js b/lib/rules/jsx-closing-bracket-location.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/jsx-closing-bracket-location.js
+++ b/lib/rules/jsx-closing-bracket-location.js
@@ -21,4 +21,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
@@ -101,5 +102,5 @@
* Get expected location for the closing bracket
* @param {Object} tokens Locations of the opening bracket, closing bracket and last prop
- * @return {String} Expected location for the closing bracket
+ * @return {string} Expected location for the closing bracket
*/
function getExpectedLocation(tokens) {
@@ -122,5 +123,5 @@
* expected location.
* @param {Object} tokens Locations of the opening bracket, closing bracket and last prop
- * @param {String} expectedLocation Expected location for the closing bracket
+ * @param {string} expectedLocation Expected location for the closing bracket
* @return {?Number} The correct column for the closing bracket, or null
*/
@@ -141,6 +142,6 @@
* Check if the closing bracket is correctly located
* @param {Object} tokens Locations of the opening bracket, closing bracket and last prop
- * @param {String} expectedLocation Expected location for the closing bracket
- * @return {Boolean} True if the closing bracket is correctly located, false if not
+ * @param {string} expectedLocation Expected location for the closing bracket
+ * @return {boolean} True if the closing bracket is correctly located, false if not
*/
function hasCorrectLocation(tokens, expectedLocation) {
@@ -164,7 +165,7 @@
* Get the characters used for indentation on the line to be matched
* @param {Object} tokens Locations of the opening bracket, closing bracket and last prop
- * @param {String} expectedLocation Expected location for the closing bracket
- * @param {Number} [correctColumn] Expected column for the closing bracket. Default to 0
- * @return {String} The characters used for indentation
+ * @param {string} expectedLocation Expected location for the closing bracket
+ * @param {number} [correctColumn] Expected column for the closing bracket. Default to 0
+ * @return {string} The characters used for indentation
*/
function getIndentation(tokens, expectedLocation, correctColumn) {
@@ -236,5 +237,5 @@
*
* @param {ASTNode} node The AST node being checked.
- * @returns {String} Unique ID (based on its range)
+ * @returns {string} Unique ID (based on its range)
*/
function getOpeningElementId(node) {
diff --git a/lib/rules/jsx-curly-brace-presence.js b/lib/rules/jsx-curly-brace-presence.js
index v7.35.0..v7.37.2 100755
--- a/lib/rules/jsx-curly-brace-presence.js
+++ b/lib/rules/jsx-curly-brace-presence.js
@@ -32,4 +32,106 @@
const DEFAULT_CONFIG = { props: OPTION_NEVER, children: OPTION_NEVER, propElementValues: OPTION_IGNORE };
+const HTML_ENTITY_REGEX = () => /&[A-Za-z\d#]+;/g;
+
+function containsLineTerminators(rawStringValue) {
+ return /[\n\r\u2028\u2029]/.test(rawStringValue);
+}
+
+function containsBackslash(rawStringValue) {
+ return arrayIncludes(rawStringValue, '\\');
+}
+
+function containsHTMLEntity(rawStringValue) {
+ return HTML_ENTITY_REGEX().test(rawStringValue);
+}
+
+function containsOnlyHtmlEntities(rawStringValue) {
+ return rawStringValue.replace(HTML_ENTITY_REGEX(), '').trim() === '';
+}
+
+function containsDisallowedJSXTextChars(rawStringValue) {
+ return /[{<>}]/.test(rawStringValue);
+}
+
+function containsQuoteCharacters(value) {
+ return /['"]/.test(value);
+}
+
+function containsMultilineComment(value) {
+ return /\/\*/.test(value);
+}
+
+function escapeDoubleQuotes(rawStringValue) {
+ return rawStringValue.replace(/\\"/g, '"').replace(/"/g, '\\"');
+}
+
+function escapeBackslashes(rawStringValue) {
+ return rawStringValue.replace(/\\/g, '\\\\');
+}
+
+function needToEscapeCharacterForJSX(raw, node) {
+ return (
+ containsBackslash(raw)
+ || containsHTMLEntity(raw)
+ || (node.parent.type !== 'JSXAttribute' && containsDisallowedJSXTextChars(raw))
+ );
+}
+
+function containsWhitespaceExpression(child) {
+ if (child.type === 'JSXExpressionContainer') {
+ const value = child.expression.value;
+ return value ? jsxUtil.isWhiteSpaces(value) : false;
+ }
+ return false;
+}
+
+function isLineBreak(text) {
+ return containsLineTerminators(text) && text.trim() === '';
+}
+
+function wrapNonHTMLEntities(text) {
+ const HTML_ENTITY = '<HTML_ENTITY>';
+ const withCurlyBraces = text.split(HTML_ENTITY_REGEX()).map((word) => (
+ word === '' ? '' : `{${JSON.stringify(word)}}`
+ )).join(HTML_ENTITY);
+
+ const htmlEntities = text.match(HTML_ENTITY_REGEX());
+ return htmlEntities.reduce((acc, htmlEntity) => (
+ acc.replace(HTML_ENTITY, htmlEntity)
+ ), withCurlyBraces);
+}
+
+function wrapWithCurlyBraces(rawText) {
+ if (!containsLineTerminators(rawText)) {
+ return `{${JSON.stringify(rawText)}}`;
+ }
+
+ return rawText.split('\n').map((line) => {
+ if (line.trim() === '') {
+ return line;
+ }
+ const firstCharIndex = line.search(/[^\s]/);
+ const leftWhitespace = line.slice(0, firstCharIndex);
+ const text = line.slice(firstCharIndex);
+
+ if (containsHTMLEntity(line)) {
+ return `${leftWhitespace}${wrapNonHTMLEntities(text)}`;
+ }
+ return `${leftWhitespace}{${JSON.stringify(text)}}`;
+ }).join('\n');
+}
+
+function isWhiteSpaceLiteral(node) {
+ return node.type && node.type === 'Literal' && node.value && jsxUtil.isWhiteSpaces(node.value);
+}
+
+function isStringWithTrailingWhiteSpaces(value) {
+ return /^\s|\s$/.test(value);
+}
+
+function isLiteralWithTrailingWhiteSpaces(node) {
+ return node.type && node.type === 'Literal' && node.value && isStringWithTrailingWhiteSpaces(node.value);
+}
+
// ------------------------------------------------------------------------------
// Rule Definition
@@ -75,5 +177,4 @@
create(context) {
- const HTML_ENTITY_REGEX = () => /&[A-Za-z\d#]+;/g;
const ruleOptions = context.options[0];
const userConfig = typeof ruleOptions === 'string'
@@ -81,92 +182,4 @@
: Object.assign({}, DEFAULT_CONFIG, ruleOptions);
- function containsLineTerminators(rawStringValue) {
- return /[\n\r\u2028\u2029]/.test(rawStringValue);
- }
-
- function containsBackslash(rawStringValue) {
- return arrayIncludes(rawStringValue, '\\');
- }
-
- function containsHTMLEntity(rawStringValue) {
- return HTML_ENTITY_REGEX().test(rawStringValue);
- }
-
- function containsOnlyHtmlEntities(rawStringValue) {
- return rawStringValue.replace(HTML_ENTITY_REGEX(), '').trim() === '';
- }
-
- function containsDisallowedJSXTextChars(rawStringValue) {
- return /[{<>}]/.test(rawStringValue);
- }
-
- function containsQuoteCharacters(value) {
- return /['"]/.test(value);
- }
-
- function containsMultilineComment(value) {
- return /\/\*/.test(value);
- }
-
- function escapeDoubleQuotes(rawStringValue) {
- return rawStringValue.replace(/\\"/g, '"').replace(/"/g, '\\"');
- }
-
- function escapeBackslashes(rawStringValue) {
- return rawStringValue.replace(/\\/g, '\\\\');
- }
-
- function needToEscapeCharacterForJSX(raw, node) {
- return (
- containsBackslash(raw)
- || containsHTMLEntity(raw)
- || (node.parent.type !== 'JSXAttribute' && containsDisallowedJSXTextChars(raw))
- );
- }
-
- function containsWhitespaceExpression(child) {
- if (child.type === 'JSXExpressionContainer') {
- const value = child.expression.value;
- return value ? jsxUtil.isWhiteSpaces(value) : false;
- }
- return false;
- }
-
- function isLineBreak(text) {
- return containsLineTerminators(text) && text.trim() === '';
- }
-
- function wrapNonHTMLEntities(text) {
- const HTML_ENTITY = '<HTML_ENTITY>';
- const withCurlyBraces = text.split(HTML_ENTITY_REGEX()).map((word) => (
- word === '' ? '' : `{${JSON.stringify(word)}}`
- )).join(HTML_ENTITY);
-
- const htmlEntities = text.match(HTML_ENTITY_REGEX());
- return htmlEntities.reduce((acc, htmlEntity) => (
- acc.replace(HTML_ENTITY, htmlEntity)
- ), withCurlyBraces);
- }
-
- function wrapWithCurlyBraces(rawText) {
- if (!containsLineTerminators(rawText)) {
- return `{${JSON.stringify(rawText)}}`;
- }
-
- return rawText.split('\n').map((line) => {
- if (line.trim() === '') {
- return line;
- }
- const firstCharIndex = line.search(/[^\s]/);
- const leftWhitespace = line.slice(0, firstCharIndex);
- const text = line.slice(firstCharIndex);
-
- if (containsHTMLEntity(line)) {
- return `${leftWhitespace}${wrapNonHTMLEntities(text)}`;
- }
- return `${leftWhitespace}{${JSON.stringify(text)}}`;
- }).join('\n');
- }
-
/**
* Report and fix an unnecessary curly brace violation on a node
@@ -187,8 +200,12 @@
if (parentType === 'JSXAttribute') {
- textToReplace = `"${expressionType === 'TemplateLiteral'
- ? expression.quasis[0].value.raw
- : expression.raw.slice(1, -1)
- }"`;
+ if (expressionType !== 'TemplateLiteral' && /["]/.test(expression.raw.slice(1, -1))) {
+ textToReplace = expression.raw;
+ } else {
+ textToReplace = `"${expressionType === 'TemplateLiteral'
+ ? expression.quasis[0].value.raw
+ : expression.raw.slice(1, -1)
+ }"`;
+ }
} else if (jsxUtil.isJSX(expression)) {
textToReplace = getText(context, expression);
@@ -234,16 +251,4 @@
}
- function isWhiteSpaceLiteral(node) {
- return node.type && node.type === 'Literal' && node.value && jsxUtil.isWhiteSpaces(node.value);
- }
-
- function isStringWithTrailingWhiteSpaces(value) {
- return /^\s|\s$/.test(value);
- }
-
- function isLiteralWithTrailingWhiteSpaces(node) {
- return node.type && node.type === 'Literal' && node.value && isStringWithTrailingWhiteSpaces(node.value);
- }
-
// Bail out if there is any character that needs to be escaped in JSX
// because escaping decreases readability and the original code may be more
@@ -269,5 +274,5 @@
&& !needToEscapeCharacterForJSX(expression.raw, JSXExpressionNode) && (
jsxUtil.isJSX(JSXExpressionNode.parent)
- || !containsQuoteCharacters(expression.value)
+ || (!containsQuoteCharacters(expression.value) || typeof expression.value === 'string')
)
) {
diff --git a/lib/rules/jsx-curly-spacing.js b/lib/rules/jsx-curly-spacing.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/jsx-curly-spacing.js
+++ b/lib/rules/jsx-curly-spacing.js
@@ -36,4 +36,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
diff --git a/lib/rules/jsx-equals-spacing.js b/lib/rules/jsx-equals-spacing.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/jsx-equals-spacing.js
+++ b/lib/rules/jsx-equals-spacing.js
@@ -21,4 +21,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
diff --git a/lib/rules/jsx-first-prop-new-line.js b/lib/rules/jsx-first-prop-new-line.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/jsx-first-prop-new-line.js
+++ b/lib/rules/jsx-first-prop-new-line.js
@@ -8,4 +8,5 @@
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const propsUtil = require('../util/props');
// ------------------------------------------------------------------------------
@@ -56,5 +57,6 @@
node: decl,
fix(fixer) {
- return fixer.replaceTextRange([(node.typeParameters || node.name).range[1], decl.range[0]], '\n');
+ const nodeTypeArguments = propsUtil.getTypeArguments(node);
+ return fixer.replaceTextRange([(nodeTypeArguments || node.name).range[1], decl.range[0]], '\n');
},
});
diff --git a/lib/rules/jsx-fragments.js b/lib/rules/jsx-fragments.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/jsx-fragments.js
+++ b/lib/rules/jsx-fragments.js
@@ -23,10 +23,10 @@
const messages = {
- fragmentsNotSupported: 'Fragments are only supported starting from React v16.2. '
- + 'Please disable the `react/jsx-fragments` rule in `eslint` settings or upgrade your version of React.',
+ fragmentsNotSupported: 'Fragments are only supported starting from React v16.2. Please disable the `react/jsx-fragments` rule in `eslint` settings or upgrade your version of React.',
preferPragma: 'Prefer {{react}}.{{fragment}} over fragment shorthand',
preferFragment: 'Prefer fragment shorthand over {{react}}.{{fragment}}',
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
@@ -171,5 +171,5 @@
if (node.source && node.source.value === 'react') {
node.specifiers.forEach((spec) => {
- if (spec.imported && spec.imported.name === fragmentPragma) {
+ if ('imported' in spec && spec.imported && spec.imported.name === fragmentPragma) {
if (spec.local) {
fragmentNames.add(spec.local.name);
diff --git a/lib/rules/jsx-indent-props.js b/lib/rules/jsx-indent-props.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/jsx-indent-props.js
+++ b/lib/rules/jsx-indent-props.js
@@ -46,4 +46,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
@@ -117,6 +118,6 @@
* Reports a given indent violation and properly pluralizes the message
* @param {ASTNode} node Node violating the indent rule
- * @param {Number} needed Expected indentation character count
- * @param {Number} gotten Indentation character count in the actual node/code
+ * @param {number} needed Expected indentation character count
+ * @param {number} gotten Indentation character count in the actual node/code
*/
function report(node, needed, gotten) {
@@ -142,5 +143,5 @@
* Get node indent
* @param {ASTNode} node Node to examine
- * @return {Number} Indent
+ * @return {number} Indent
*/
function getNodeIndent(node) {
@@ -174,5 +175,5 @@
* Check indent for nodes list
* @param {ASTNode[]} nodes list of node objects
- * @param {Number} indent needed indent
+ * @param {number} indent needed indent
*/
function checkNodesIndent(nodes, indent) {
diff --git a/lib/rules/jsx-indent.js b/lib/rules/jsx-indent.js
index v7.35.0..v7.37.2 100644
--- a/lib/rules/jsx-indent.js
+++ b/lib/rules/jsx-indent.js
@@ -51,4 +51,5 @@
};
+/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
@@ -106,5 +107,5 @@
* Responsible for fixing the indentation issue fix
* @param {ASTNode} node Node violating the indent rule
- * @param {Number} needed Expected indentation character count
+ * @param {number} needed Expected indentation character count
* @returns {Function} function to be executed by the fixer
* @private
@@ -147,6 +148,6 @@
* Reports a given indent violation and properly pluralizes the message
* @param {ASTNode} node Node violating the indent rule
- * @param {Number} needed Expected indentation character count
- * @param {Number} gotten Indentation character count in the actual node/code
+ * @param {number} needed Expected indentation character count
+ * @param {number} gotten Indentation character count in the actual node/code
* @param {Object} [loc] Error line and column location
*/
@@ -169,7 +170,7 @@
* Get node indent
* @param {ASTNode} node Node to examine
- * @param {Boolean} [byLastLine] get indent of node's last line
- * @param {Boolean} [excludeCommas] skip comma on start of line
- * @return {Number} Indent
+ * @param {boolean} [byLastLine] get indent of node's last line
+ * @param {boolean} [excludeCommas] skip comma on start of line
+ * @return {number} Indent
*/
function getNodeIndent(node, byLastLine, excludeCommas) {
@@ -198,5 +199,5 @@
* Check if the node is the right member of a logical expression
* @param {ASTNode} node The node to check
- * @return {Boolean} true if its the case, false if not
+ * @return {boolean} true if its the case, false if not
*/
function isRightInLogicalExp(node) {
@@ -213,5 +214,5 @@
* Check if the node is the alternate member of a conditional expression
* @param {ASTNode} node The node to check
- * @return {Boolean} true if its the case, false if not
+ * @return {boolean} true if its the case, false if not
*/
function isAlternateInConditionalExp(node) {
@@ -228,5 +229,5 @@
* Check if the node is within a DoExpression block but not the first expression (which need to be indented)
* @param {ASTNode} node The node to check
- * @return {Boolean} true if its the case, false if not
+ * @return {boolean} true if its the case, false if not
*/
function isSecondOrSubsequentExpWithinDoExp(node) {
@@ -299,6 +300,6 @@
* Check indent for nodes list
* @param {ASTNode} node The node to check
- * @param {Number} indent needed indent
- * @param {Boolean} [excludeCommas] skip comma on start of line
+ * @param {number} indent needed indent
+ * @param {boolean} [excludeCommas] skip comma on start of line
*/
function checkNodesIndent(node, indent, excludeCommas) {
@@ -319,5 +320,5 @@
* Check indent for Literal Node or JSXText Node
* @param {ASTNode} node The node to check
- * @param {Number (too long so truncated)
Command detailsnpm diff --diff=eslint-plugin-react@7.35.0 --diff=eslint-plugin-react@7.37.2 --diff-unified=2 See also the Reported by ybiquitous/npm-diff-action@v1.6.0 (Node.js 22.11.0 and npm 10.9.0) |
dependabot
bot
force-pushed
the
dependabot/npm_and_yarn/eslint-plugin-react-7.37.2
branch
2 times, most recently
from
November 1, 2024 03:08
6cb276d
to
121a49e
Compare
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.35.0 to 7.37.2. - [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases) - [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md) - [Commits](jsx-eslint/eslint-plugin-react@v7.35.0...v7.37.2) --- updated-dependencies: - dependency-name: eslint-plugin-react dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
dependabot
bot
force-pushed
the
dependabot/npm_and_yarn/eslint-plugin-react-7.37.2
branch
from
November 1, 2024 03:10
121a49e
to
d73e796
Compare
ybiquitous
changed the title
build(deps): bump eslint-plugin-react from 7.35.0 to 7.37.2
feat(deps): bump eslint-plugin-react from 7.35.0 to 7.37.2
Nov 5, 2024
github-actions
bot
deleted the
dependabot/npm_and_yarn/eslint-plugin-react-7.37.2
branch
November 5, 2024 05:55
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
dependencies
Pull requests that update a dependency file
javascript
Pull requests that update Javascript code
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Bumps eslint-plugin-react from 7.35.0 to 7.37.2.
Release notes
Sourced from eslint-plugin-react's releases.
... (truncated)
Changelog
Sourced from eslint-plugin-react's changelog.
... (truncated)
Commits
256cf74
Update CHANGELOG and bump version33db656
[Deps] updatees-iterator-helpers
5696f99
[Dev Deps] update@babel/core
,@babel/eslint-parser
, `@babel/plugin-synta...5c23573
[Dev Deps] update@babel/core,
@babel/eslint-parser
,
@babel/plugin-syntax
...c47fa56
[types] [Fix] ensure the index types are generated63aceff
[Fix]destructuring-assignment
: fix false negative when usingtypeof props.a
96d46d5
[Refactor]destructuring-assignment
: usegetParentStatelessComponent
ae6fb8d
Update CHANGELOG and bump version63e0b49
[meta] do not npmignored.ts
files1f95a24
[readme] Fix shared settings linkDependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase
.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebase
will rebase this PR@dependabot recreate
will recreate this PR, overwriting any edits that have been made to it@dependabot merge
will merge this PR after your CI passes on it@dependabot squash and merge
will squash and merge this PR after your CI passes on it@dependabot cancel merge
will cancel a previously requested merge and block automerging@dependabot reopen
will reopen this PR if it is closed@dependabot close
will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot show <dependency name> ignore conditions
will show all of the ignore conditions of the specified dependency@dependabot ignore this major version
will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor version
will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependency
will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)